package ms.unicorn.dsl.utils;

import java.io.File;
import java.util.regex.Pattern;

import ms.unicorn.dsl.runtime.ExecutionContext;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.resource.DefaultLocationInFileProvider;
import org.eclipse.xtext.resource.ILocationInFileProvider;
import org.eclipse.xtext.util.Strings;


public class SphynxRuntimeException extends RuntimeException {

	private static final long serialVersionUID = 1L;
	private ExecutionContext context;
	private EObject element;

	public SphynxRuntimeException(ExecutionContext context) {
		this.setContext(context);
	}
	
	public SphynxRuntimeException(ExecutionContext context, EObject element) {
		this.setContext(context);
		this.setElement(element);
	}

	public SphynxRuntimeException(ExecutionContext context, EObject element, String arg0) {
		super(arg0);
		this.setContext(context);
		this.setElement(element);
	}

	public SphynxRuntimeException(ExecutionContext context, EObject element, Throwable cause) {
		super(cause);
		this.setContext(context);
		this.setElement(element);
	}

	public SphynxRuntimeException(ExecutionContext context, EObject element, String message, Throwable cause) {
		super(message, cause);
		this.setContext(context);
		this.setElement(element);
	}

	public ExecutionContext getContext() {
		return context;
	}

	public void setContext(ExecutionContext context) {
		this.context = context;
		if (context != null)
			element = context.getEvaluatingExpression();
	}

	public EObject getElement() {
		return element;
	}

	public void setElement(EObject element) {
		if (element != null)
			this.element = element;
	}

	@Override
	public String toString() {
		return  super.toString() + " " + getLocation(true)  ;
	}
	
	static ILocationInFileProvider sourceLocator = new DefaultLocationInFileProvider();
	static Pattern countLinePattern = Pattern.compile("\n", Pattern.MULTILINE);
 	
	private int[] resolveNodeLocation(INode node) {
		//int line = node.getStartLine();
		int offset = node.getOffset();
		INode rootNode = node.getRootNode();
		String fulltext = rootNode.getText();
		String leadingText = fulltext.substring(0, offset);
		
		int line = Strings.countLines(leadingText) + 1;
		int idx = leadingText.lastIndexOf("\n");
		int col = offset - idx - 1;
		// expand tab characters
		
		for(int i = idx; i < offset; i++)
			if (fulltext.charAt(i) == '\t')
				col += 3; // a tab character is equivalent to 4 spaces 
		return new int[] {line, col + 1};
	}
	
	public String getLocation(boolean shortFilename) {
		String result = "";
		try {
			EObject e = element != null ? element : context != null ? context.getEvaluatingExpression() : null;
			if (e != null && context != null && e.eResource() != null) {
				URI uri = e.eResource().getURI();
				String filename = uri.isFile() ? uri.toFileString() : "?";
				if (shortFilename)
					filename = new File(filename).getName();
				Adapter adapter = e.eAdapters().get(0);
				if (adapter instanceof INode) {
					INode node = (INode) adapter;
					int[] loc = resolveNodeLocation(node);
					result = String.format("(%s:%d,%d)", filename, loc[0], loc[1]);
				}				
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
}
